﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;

namespace Latermoon.Plugin.Bookmark
{
    /// <summary>
    /// 提供一组方法从收藏夹备份构建XmlDocument
    /// 节点格式:root/folder/a
    /// </summary>
    public class BookmarkDocument : XmlDocument
    {
        public BookmarkDocument()
        {
            base.LoadXml(string.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- Generated By Latermoon.Plugin.Bookmark.BookmarkDocument {0}--><root name=\"\"></root >", DateTime.Now.ToString()));
        }

        /// <summary>
        /// 从收藏夹导出的备份文件载入
        /// </summary>
        /// <param name="filename"></param>
        public new void Load(string filename)
        {
            LoadText(File.ReadAllText(filename, Encoding.Default));
        }

        /// <summary>
        /// 从包含收藏夹导出内容的Stream载入
        /// </summary>
        /// <param name="stream"></param>
        public new void Load(Stream stream)
        {
            StreamReader streamReader = new StreamReader(stream, Encoding.Default);
            LoadText(streamReader.ReadToEnd());
        }

        /// <summary>
        /// 不支持该方法
        /// </summary>
        /// <param name="reader"></param>
        public new void Load(XmlReader reader)
        {
            throw new NotSupportedException("不支持从XML导入");
        }

        /// <summary>
        /// 从包含收藏夹导出内容的TextReader载入
        /// </summary>
        /// <param name="reader"></param>
        public new void Load(TextReader reader)
        {
            LoadText(reader.ReadToEnd());
        }

        /// <summary>
        /// 不支持该方法
        /// </summary>
        /// <param name="bookmark"></param>
        public new void LoadXml(string bookmark)
        {
            throw new NotSupportedException("不支持从XML导入");
        }

        /// <summary>
        /// 从收藏夹导出文本载入
        /// </summary>
        /// <param name="bookmarkContent"></param>
        public void LoadText(string bookmarkContent)
        {
            //存放当前父文件夹的堆栈
            Stack<XmlNode> folderStack = new Stack<XmlNode>();
            //逐行读取文件
            StringReader reader = new StringReader(bookmarkContent);
            string line = null;
            //当前处理中的父文件夹
            XmlNode curParent = null;
            //当前处理的文件夹
            XmlNode curFolder = this.DocumentElement;
            while ((line = reader.ReadLine() )!= null)
            {
                line = line.Trim();
                if (line == string.Empty)
                {
                    continue;
                }
                //遇到该符号表示开始分析子文件夹
                if (line.StartsWith("<dl><p>", StringComparison.OrdinalIgnoreCase))
                {   
                    //将当前处理目录入栈
                    folderStack.Push(curFolder);
                    //并设为当前要处理的父文件夹
                    curParent = curFolder;
                }
                else if (line.StartsWith("<dt><h3", StringComparison.OrdinalIgnoreCase))
                {
                    //表示添加一个子文件夹
                    curFolder = this.CreateElement("folder");
                    curFolder.Attributes.Append(this.CreateAttribute("name")).Value = Regex.Replace(line, "<[^>]*>", "");
                    curFolder.Attributes.Append(this.CreateAttribute("ADD_DATE")).Value = GetAttribute(line, "ADD_DATE");
                    curParent.AppendChild(curFolder);
                }
                else if (line.StartsWith("<dt><a", StringComparison.OrdinalIgnoreCase))
                {
                    //表示添加一条超链接
                    XmlNode link = this.CreateElement("a");
                    link.InnerText = Regex.Replace(line, "<[^>]*>", "");
                    link.Attributes.Append(this.CreateAttribute("href")).Value = GetAttribute(line, "HREF");
                    link.Attributes.Append(this.CreateAttribute("ADD_DATE")).Value = GetAttribute(line, "ADD_DATE");
                    link.Attributes.Append(this.CreateAttribute("LAST_VISIT")).Value = GetAttribute(line, "LAST_VISIT");
                    link.Attributes.Append(this.CreateAttribute("LAST_MODIFIED")).Value = GetAttribute(line, "LAST_MODIFIED");
                    //将网址的全部父级文件夹名作为它的tag
                    link.Attributes.Append(this.CreateAttribute("tag")).Value = FolderStackToTag(folderStack);

                    curParent.AppendChild(link);
                }
                else if (line.StartsWith("</dl><p>", StringComparison.OrdinalIgnoreCase))
                {
                    //分析当前目录完毕，出栈
                    folderStack.Pop();
                    //堆栈为空时结束分析
                    if (folderStack.Count == 0)
                    {
                        break;
                    }
                    //堆栈不为空, 回到上级文件夹继续处理
                    curParent = folderStack.Peek();
                }
                else
                {
                    Console.WriteLine("ignored: " + line);
                }
            }
        }

        /// <summary>
        /// 将节点所在文件夹以及父文件夹转成tag
        /// </summary>
        /// <param name="stack"></param>
        /// <returns></returns>
        private string FolderStackToTag(Stack<XmlNode> stack)
        {
            StringBuilder buffer = new StringBuilder();
            XmlNode[] nodes = stack.ToArray();
            //反向添加tag
            string separator = ",";
            for (int i = nodes.Length - 1; i >= 0; i--)
            {
                XmlAttribute attr = nodes[i].Attributes["name"];
                if (attr == null || attr.Value == string.Empty)
                {
                    continue;
                }
                buffer.Append(attr.Value);
                buffer.Append(separator);
            }
            //移除最后的逗号
            if (buffer.Length > 0)
            {
                buffer.Remove(buffer.Length - separator.Length, separator.Length);
            }
            return buffer.ToString();
        }

        /// <summary>
        /// 获取html属性
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        private string GetAttribute(string input, string name)
        {
            string regexpattern = string.Format("<*[^><]*{0}=\"([^\"]*?)\"[^><]*>", name);
            Regex regex = new Regex(regexpattern, RegexOptions.IgnoreCase);
            Match match = regex.Match(input);
            return match.Groups[1].Value;
        }

        /// <summary>
        /// 根文件夹
        /// </summary>
        public BookmarkFolder RootFolder
        {
            get
            {
                return new BookmarkFolder(this.DocumentElement);
            }
        }
    }
}
